/* Copyright 2010 John L. Reilly

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */

package com.riq;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.logging.Logger;

import javax.jdo.PersistenceManager;
import javax.mail.Address;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.riq.entity.Alert;
import com.riq.entity.Location;
import com.riq.entity.Member;
import com.riq.entity.Tracking;

public class VoicemailHandlerServlet extends HttpServlet {

	private static final long serialVersionUID = 1L;
	private static final Logger log = Logger.getLogger(VoicemailHandlerServlet.class.getName());
	private String responseType = "";
	
	private boolean textIsHtml = false;
	
	private String getText(Part p) throws
    MessagingException, IOException {
	  
	  log.info("Inside VoiceMailServlet getText v2");
	
		if (p.isMimeType("text/*")) { 
			String s = (String)p.getContent();
			boolean textIsHtml = p.isMimeType("text/html");
			return s;
			}
		
		if (p.isMimeType("multipart/alternative")) {
			Multipart mp = (Multipart)p.getContent();
			String text = null;
			for (int i = 0; i < mp.getCount(); i++) {
			    Part bp = mp.getBodyPart(i);
			    if (bp.isMimeType("text/plain")) {
			        if (text == null)
			            text = getText(bp);
			        continue;
			    } else if (bp.isMimeType("text/html")) {
			        String s = getText(bp);
			        if (s != null)
			            return s;
			    } else {
			        return getText(bp);
			    }
		}
		return text;
		
		} else if (p.isMimeType("multipart/*")) {
			Multipart mp = (Multipart)p.getContent();
			for (int i = 0; i < mp.getCount(); i++) {
			    String s = getText(mp.getBodyPart(i));
			    if (s != null)
			        return s;
			}
		}
		return null;
  }
	
	
  public void doPost(HttpServletRequest request, HttpServletResponse response) 
      throws IOException {
    	
      log.info("Inside VoiceMailServlet doPost v2");
    	PersistenceManager pm = PMF.get().getPersistenceManager();
	    Properties props = new Properties(); 
	    Session session = Session.getDefaultInstance(props, null); 
          
	  try {
		
	    Message msg;
		msg = new MimeMessage(session, request.getInputStream());
		String msgText = getText(msg);
			
		Address[] toArray;
	    Address[] fromArray;
	    Address toAddress = null;
	    Address fromAddress = null;
	    String rawTo = "";
	    String rawFrom = "";

	    fromArray = msg.getFrom();
	    fromAddress = fromArray[0];
	    rawFrom = fromAddress.toString();
	      
	    toArray = msg.getAllRecipients();
	    toAddress = toArray[0];
	    rawTo = toAddress.toString(); 
			
	    String callerId = "";		
	    String selectedVRU = "";
			
	    log.info("Msg type: " + msg.getContentType());
	    log.info("Msg rawTo: " + rawTo);
	    log.info("Msg rawFrom: " + rawFrom);
	    log.info("Msg Content: " + msg.getContent().toString());

        // android messages come from txt.voice.google.com
	    
	    log.info("sub1: " + msgText.substring(0, 5));
		//      log.info("sub1: " + msgText.substring(5, 50));
		//      log.info("sub2: " + msgText.substring(50, 100));
		//      log.info("sub3: " + msgText.substring(100, 150));
		//      log.info("sub4: " + msgText.substring(150, 200));
		//      log.info("sub5: " + msgText.substring(200, 250));
		//      log.info("sub6: " + msgText.substring(250, 300));
		//      log.info("sub7: " + msgText.substring(300, 350));
		//      log.info("sub8: " + msgText.substring(350, 400));
		//      log.info("sub9: " + msgText.substring(400, 450));
		//      log.info("sub10: " + msgText.substring(450, 500));
		//      log.info("sub11: " + msgText.substring(500, 550));
      
      String tempGoogle = "no";
      
      if (rawFrom.contains("txt.voice.google.com")) {
    	  
    	  // tempGoogle set for valid inbound messages
	      tempGoogle = "yes";
	        
		  callerId = rawFrom.substring(rawFrom.indexOf(".")+2, rawFrom.indexOf(".")+12); 
	      log.info("CallerId SMS: " + callerId.trim());
	      
	      selectedVRU = rawTo.replaceAll("\\D","");
	      log.info("VRU SMS: " + selectedVRU.trim());

      // google voice messages come from voice-noreply@google.com
      
      } else if (rawFrom.contains("voice-noreply@google.com")) {
    
        if (msgText.contains("Voicemail from:")) {
        	
      	  // tempGoogle set for valid inbound messages
          tempGoogle = "yes";
        
          callerId = msgText.substring(msgText.indexOf("Voicemail from:"));
          callerId = callerId.replaceAll("\\D","");
          callerId = callerId.substring(0, 10).trim();
          log.info("CallerId Voice: " + callerId.trim());
          selectedVRU = rawTo.replaceAll("\\D","");
          log.info("VRU Voice Message: " + selectedVRU.trim());
          responseType = "memberVoiceComplete";

        } else if (msgText.contains("Missed call from:")) {
          
      	  // tempGoogle set for valid inbound messages
          tempGoogle = "yes";
          
          callerId = msgText.substring(msgText.indexOf("Missed call from:"));
          callerId = callerId.replaceAll("\\D","");
          callerId = callerId.substring(0, 10).trim();
          log.info("CallerId Voice: " + callerId.trim());
          selectedVRU = rawTo.replaceAll("\\D","");
          log.info("VRU Voice Missed: " + selectedVRU.trim());
          responseType = "memberVoiceMissed";

//        } else if (msgText.contains("SMS")) {
//        	
//          tempGoogle = "yes";
//            
//          callerId = msgText.substring(msgText.indexOf("SMS"));
//          callerId = callerId.replaceAll("\\D","");
//          callerId = callerId.substring(0, 10).trim();
//          log.info("SenderId Voice SMS: " + callerId.trim());
//          selectedVRU = rawTo.replaceAll("\\D","");
//          log.info("VRU Voice SMS: " + selectedVRU.trim());
//          responseType = "memberVoiceSMS";
        }
     }
          
  if ("yes".equalsIgnoreCase(tempGoogle)) {
      
	    // work around for query limitation in Google App Engine (or developer's expertise :)
	    // note: Dept is not known since multiple Depts might use one Google Voice phone number.
	  
//	    Query q1 = pm.newQuery("select id from " + Member.class.getName() +
//	    " where callerId1 == '" + callerId.trim() + "' ");
//	    List<Long> members1 = (List<Long>) q1.execute();
//	    
//	    Query q2 = pm.newQuery("select id from " + Member.class.getName() +
//	    " where callerId1 == '" + callerId.trim() + "' ");
//	    List<Long> members2 = (List<Long>) q2.execute();
//	    	    
//	    Query q3 = pm.newQuery("select id from " + Member.class.getName() +
//	    " where callerId1 == '" + callerId.trim() + "' ");
//	    List<Long> members3 = (List<Long>) q3.execute();
	  
  		String queryMembers1 = 	" select id from " + Member.class.getName() + 
		" where callerId1 == '" + callerId.trim() + "' ";
		List<Long> members1 = (List<Long>) pm.newQuery(queryMembers1).execute();  
		
  		String queryMembers2 = 	" select id from " + Member.class.getName() + 
		" where callerId2 == '" + callerId.trim() + "' ";
		List<Long> members2 = (List<Long>) pm.newQuery(queryMembers2).execute();  
		
  		String queryMembers3 = 	" select id from " + Member.class.getName() + 
		" where callerId3 == '" + callerId.trim() + "' ";
		List<Long> members3 = (List<Long>) pm.newQuery(queryMembers3).execute();  
		
	    List<Long> memberIds = new ArrayList<Long>();
	    memberIds.addAll(members1);
	    memberIds.addAll(members2);
	    memberIds.addAll(members3);
        
        // proceed if there is a Member with this caller id...
	    if (memberIds.size() != 0) {
		  
	    Member targetMember = pm.getObjectById(Member.class, memberIds.get(0));
		log.info("There is a matching member for this vm");
		 
	 	// find the location that has the corresponding vru number
		String queryLocations = " select from " + Location.class.getName() + 
		                        " where deptId == " + targetMember.getdeptId() +
		                        " && vru == '" + selectedVRU + "' ";
		List<Location> locations = (List<Location>) pm.newQuery(queryLocations).execute();
        log.info("Locations Size Fri: " + locations.size());

		Long locationId = locations.get(0).getid();
		
		// find the most recent alert (sorting alerts by timestamp in descending order
		String queryAlerts = " select from " + Alert.class.getName() + 
							 " where deptId == " + targetMember.getdeptId() + 
		                     " && status == 'Active' order by timeStamp desc ";
		List<Alert> alerts = (List<Alert>) pm.newQuery(queryAlerts).execute();
        log.info("Alerts Size Fri: " + alerts.size());

		Long alertId = alerts.get(0).getid();
		
		// check to make sure there's an active Alert and a properly configured default Location
		if (locations.size() > 0 && alerts.size() > 0) {
			
          Tracking t = new Tracking (
            targetMember.getdeptId(),
            alertId,
            locationId,
            System.currentTimeMillis(),
            null,  // TODO: johnreilly authorId tbd
            "member",
            targetMember.getid(),
            null,
            responseType
            );
          pm.makePersistent(t);
		
	    } else {
	    	
		// no associated Location with this VRU
		String msgBodyDK = "There is no selected Location for this phone nnumber. "  + 
		                   "Contact your Department's administrator to correct this issue.";
		
		String recipientAddress = "";
		recipientAddress = msg.getFrom().toString();
		log.info("No location VRU: " + msg.getFrom());
		
		String senderAddress = "";
		senderAddress = "jreilly@gmail.com";
		
		log.info("To: " + recipientAddress);
		log.info("Msg: " + msgBodyDK);
		
		Message msgUnknownCallerId = new MimeMessage(session);
		msgUnknownCallerId.setFrom(new InternetAddress(senderAddress));
		msgUnknownCallerId.addRecipient(Message.RecipientType.TO, new InternetAddress(recipientAddress));
		
		msgUnknownCallerId.setSubject("Unknown Location");
		msgUnknownCallerId.setText(msgBodyDK); 
		Transport.send(msgUnknownCallerId);
	    	
	    }
		
	  } else {
		
		String msgBodyDK = "You phone number is not registered with FirstResponder. "  + 
				           "Contact your Department's administrator to correct this issue.";
		
		String recipientAddress = "";
		recipientAddress = msg.getFrom().toString();
		log.info("Member Email Address for Unknown Phone Number: " + msg.getFrom());
		
		String senderAddress = "";
		senderAddress = "jreilly@gmail.com";
		
		log.info("To: " + recipientAddress);
		log.info("Msg: " + msgBodyDK);
		
		Message msgUnknownCallerId = new MimeMessage(session);
		msgUnknownCallerId.setFrom(new InternetAddress(senderAddress));
		msgUnknownCallerId.addRecipient(Message.RecipientType.TO, new InternetAddress(recipientAddress));
		msgUnknownCallerId.setSubject("Unknown Phone Number");
		msgUnknownCallerId.setText(msgBodyDK); 
		Transport.send(msgUnknownCallerId);

		}
      }
	} catch (MessagingException e) {
	     	// TODO Auto-generated catch block
		  e.printStackTrace();
		
	} finally { pm.close(); }    
  }
}